闲扯
冲着学启发式合并来做的题,结果发现完全不懂其中的一些细节啊。。。
最后还是看了题解里面大佬的解释才想通。
题面
Solution
考虑对每一种颜色开一个平衡树,那么我们每次操作相当于是合并两颗平衡树。
直接暴力合并复杂度显然是不对的,考虑启发式合并。
每次将一颗较小的平衡树合并到一颗较大的平衡树里,每次操作较小的那个平衡树的大小至少增加一倍,所以对于每个节点来说最多被操作 $\log$ 次,所以时间复杂度为 $O(n\log n)$ 。
先处理出当前序列的答案。显然,这个答案是不会增加的。(因为增加的条件时一个连续区间被分成两段,但是每次我们都是把一种颜色全部变为另一种,所以不会出现这种情况)
对于每次合并,我们将颜色为 $x$ 的全部变为 $y$ ,和我们将颜色为 $y$ 的全部变为 $x$ 效果是一样的,所以每次将小的合并到大的里面是没问题的。
但是因为在合并之后,我们会将小的那颗平衡树清空,所以如果在我们把 $x$ 变为 $y$ 的操作中, $y$ 要较小一些,我们就直接把 $y$ 给删除了,下一次如果还要对 $y$ 操作,就会出现问题。
所以我们用一个 $fa$ 数组来存储当前颜色的代表节点。
如果 $x$ 的大小小于 $y$ 的大小,我们直接合并就好。否则我们将 $x$ 和 $y$ 的代表节点换一下,这样我们下一次调用 $y$ 时,我们找到的就是代表 $x$ 的这颗平衡树,这样就保证了算法的正确性。
不过这题我们直接用 $set$ 维护就可以了。
Code
1 |
|
总结
启发式合并第一题,很多细节没有想到,要多做题总结。